#include "LightSensor.h"

#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>

#include <cmath>
#include "Tools.h"

using namespace app::Clusters;
using namespace app::Clusters::IlluminanceMeasurement::Attributes;

namespace {
constexpr DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(illuminanceMeasurementAttrs)
    DECLARE_DYNAMIC_ATTRIBUTE(MeasuredValue::Id, INT16U, 2, 0),
    DECLARE_DYNAMIC_ATTRIBUTE(MinMeasuredValue::Id, INT16U, 2, 0),
    DECLARE_DYNAMIC_ATTRIBUTE(MaxMeasuredValue::Id, INT16U, 2, 0),
DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();

EmberAfCluster illuminanceMeasurementCluster = DECLARE_DYNAMIC_CLUSTER(
    IlluminanceMeasurement::Id,
    illuminanceMeasurementAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr);
}


LightSensor::LightSensor(const ::BasicInformation* node)
    : BridgedDevice(node) {
    ChipLogProgress(DeviceLayer, "LightSensor");
    mClusters.push_back(illuminanceMeasurementCluster);
    mMeasurement = 10;
}

void LightSensor::SetMeasuredValue(uint16_t measurement) {
    const bool changed = mMeasurement != measurement;
    ChipLogProgress(DeviceLayer, "Device[%s] new measurement=\"%d\"", GetName().c_str(), measurement);
    mMeasurement = measurement;
    if (changed) {
        NotifyStatusChanged(IlluminanceMeasurement::Id, MeasuredValue::Id);
    }
}

Protocols::InteractionModel::Status LightSensor::ReadAttribute(
    ClusterId clusterId,
    AttributeId attributeId,
    uint8_t* buffer,
    uint16_t maxReadLength) {
    if (clusterId != IlluminanceMeasurement::Id) {
        return BridgedDevice::ReadAttribute(clusterId, attributeId, buffer, maxReadLength);
    }
    ChipLogProgress(DeviceLayer, "ReadAttribute: attrId=%d, maxReadLength=%d", attributeId, maxReadLength);

    if (attributeId == MeasuredValue::Id) {
        const auto newValue = static_cast<uint16_t>(10000 * log10(mMeasurement) + 1);
        tools::GetAttr(buffer, maxReadLength, newValue);
    } else if (attributeId == MinMeasuredValue::Id) {
        tools::GetAttr(buffer, maxReadLength, static_cast<uint16_t>(1u));
    } else if (attributeId == MaxMeasuredValue::Id) {
        tools::GetAttr(buffer, maxReadLength, static_cast<uint16_t>(0xfffe));
    } else {
        return Protocols::InteractionModel::Status::UnsupportedRead;
    }
    return Protocols::InteractionModel::Status::Success;
}

ChipError LightSensor::OnReport(const DataBlock* block) {
    if (block->path.clusterId != IlluminanceMeasurement::Id) {
        return BridgedDevice::OnReport(block);
    }

    if (block->path.attributeId == MeasuredValue::Id) {
        SetMeasuredValue(static_cast<uint16_t>(block->data.asInt()));
    }
    return CHIP_NO_ERROR;
}
